Code Runner Preliminary Containerization - #77
Closed
mataiodoxion wants to merge 12 commits into
Closed
Conversation
POST /api/internal/sync-password: updates a user's password by uid, called server-to-server by the Spring backend after it completes an OAuth + student ID verified password reset, so the same account's Flask password doesn't drift out of sync with Spring's. Gated by a shared secret (INTERNAL_SYNC_KEY, compared with hmac.compare_digest for timing-safety) instead of user auth, since this is never called from a browser -- there's no existing service-to-service auth mechanism in this app to reuse, and reusing the admin-only PUT /api/user route would have meant giving Spring real Flask admin credentials. This endpoint can only ever change one user's password, and is a closed no-op if INTERNAL_SYNC_KEY is unset. Co-Authored-By: Claude Sonnet 5 <[email protected]>
GET /api/user (any logged-in user, not just admins) and the other UserAPI create/update/delete responses were including the PBKDF2 hash from User.read() in the JSON body. Adds _without_password() and applies it at every general-purpose response site; the admin-only backup/export endpoints in data_export_import_api.py are left alone since they need the hash for restore fidelity.
*** REQUIRED BEFORE THIS DEPLOYS: production runs MySQL (see __init__.py --
SQLALCHEMY_DATABASE_URI switches to MySQL whenever DB_ENDPOINT/DB_USERNAME/
DB_PASSWORD are set), a completely separate database this session had no
access to. Only the local dev SQLite DB has been migrated. Someone MUST run
this against production before/with this deploy, or every login there will
error on the missing column:
ALTER TABLE users ADD COLUMN token_version INTEGER NOT NULL DEFAULT 0;
***
Previously nothing tied an issued JWT or Flask-Login session to a specific
password: the JWT carried no exp claim at all (never expired by JWT
semantics) and no password-derived data, and Flask-Login sessions just
carried a bare user id, re-validated against fresh DB data on every request
but with no check that the underlying credential hadn't changed. A stolen
JWT or session cookie kept working indefinitely, surviving a password reset
that was meant to lock an attacker out.
Adds User.token_version, bumped in set_password() (the single funnel every
password-change path already goes through) only on an actual hash change.
JWTs now carry token_version + exp and are checked against the account's
current value in auth_required. Sessions now carry it via a composite
get_id() ("id:token_version"), checked in load_user (main.py), so a stale
session is rejected before ever reaching a @login_required route instead of
running with outdated auth state.
Verified live: fresh JWT/session -> 200, password reset -> old JWT gets 401
with an explicit "password has changed" message, old session gets redirected
to login, fresh login after the reset works again.
Contributor
|
What about this? We should not have runners broken while we fix security. todo: don't hardcodeRUNNER_URL = "http://code_runner:8591/python" |
Contributor
Author
|
Not necessarily broken; I suppose it would be better to add |
as per Mr. Mort, we don't need the security layer in local development
mataiodoxion
force-pushed
the
code-runner-sec
branch
from
September 3, 2026 17:44
625682e to
a58a0e9
Compare
Contributor
|
Good thought on .env. |
Contributor
|
I will close this until then, as it also has conflicts. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Runs the python code execution endpoint in a separate container if
.envkeyIS_PRODUCTION=true, otherwise just runs the exec locally.This fixes the main issue with reading sensitive contents of the main
flask-webcontainer like sending:{ "code": "import os; os.system('cat /app/.env')" }which is now just met with (because it's a different container)
{ "output": "cat: /app/.env: No such file or directory\n" }It might be beneficial to work on some more container hardening (especially for the kernel to prevent escapes), and setting limits for resource exhaustion, but this fixes the most glaring issues for now.